﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Timers;
using EricWillis.Pop2Ticket.Pop3;
using EricWillis.Pop2Ticket.Unfuddle;

namespace EricWillis.Pop2Ticket
{
    /// <summary>
    /// Pop2Ticket Windows service which checks for new Pop3 messages and adds them as Unfuddle tickets
    /// </summary>
    public partial class Pop2TicketService : ServiceBase
    {
        #region Privates
        
        private Timer _timer = null;
        private Settings _config = null;
        private Pop3Client _pop3 = null;
        private UnfuddleClient _unfuddle = null;
        private Boolean _failedStartup = false;

        #endregion

        #region Constructor

        public Pop2TicketService()
        {
            InitializeComponent();

            // load config file (it's just xml, don't be afraid)
            this._config = Settings.Load();

            // if _failedStartup is false, the service is going to exit OnStart after writing a template config file
            if (this._failedStartup = this._config == null)
            { // check for a config file, if none, make an xml template and bail
                this._config = new Settings();
                this._config.Interval = 60000;
                this._config.Pop3Password = "your pop3 password";
                this._config.Pop3Port = 110;
                this._config.Pop3Server = "your pop3 server";
                this._config.Pop3Username = "your pop3 username";
                this._config.Pop3UseSsl = false;
                this._config.UnfuddlePassword = "your unfuddle password";
                this._config.UnfuddleProjectID = "the unfuddle project ID to update";
                this._config.UnfuddleSubdomain = "your unfuddle subdomain";
                this._config.UnfuddleUsername = "your unfuddle username";
                this._config.UnfuddleUseSsl = false;
                this._config.UnfuddleDefaultTicketPriority = Convert.ToInt32(TicketPriority.Normal);

                this._config.Save();
            }

            // set up timer to fire on the specified interval
            this._timer = new Timer();
            this._timer.Interval = this._config.Interval;
            this._timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);

            // Pop3 client (default port is 110 and default Ssl is false)
            this._pop3 = new Pop3Client
            (
                this._config.Pop3Username,
                this._config.Pop3Password,
                this._config.Pop3Server,
                this._config.Pop3Port,
                this._config.Pop3UseSsl
            );

            // Unfuddle client (default Ssl is false)
            this._unfuddle = new UnfuddleClient
            (
                this._config.UnfuddleUsername,
                this._config.UnfuddlePassword,
                this._config.UnfuddleSubdomain,
                this._config.UnfuddleProjectID,
                this._config.UnfuddleUseSsl
            );
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Every time the interval elapses, check for new Pop3 messages and add them to Unfuddle
        /// </summary>
        private void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            this._timer.Stop(); // pause while Pop3 and Unfuddle interaction happens

            this._pop3.Connect();

            // for each new message, add a ticket to Unfuddle
            foreach (Message message in this._pop3.GetMessages())
            {
                Ticket ticket = this._unfuddle.AddTicket
                (
                    (TicketPriority)this._config.UnfuddleDefaultTicketPriority,
                    message.From,
                    message.Subject,
                    message.Body
                );

                foreach (var attachment in message.Attachments)
                {
                    if (!this._config.UnfuddleUseSsl)
                    {
                        throw new NotSupportedException("Unfuddle will only accept attachments over SSL. Please use SSL in your configuration file");
                    }

                    this._unfuddle.AddAttachment(ticket, attachment);
                }

                // delete Pop3 messages that have been inserted into Unfuddle if the config says so
                if (this._config.Pop3DeleteMessageAfterRead)
                    this._pop3.DeleteMessage(message.ID);
            }

            this._pop3.Disconnect();

            this._timer.Start(); // resume when we're done
        }

        #endregion

        #region Overridden Methods

        /// <summary>
        /// The start of the service (when the play button in services.msc is pushed) or during: net start _service_
        /// </summary>
        protected override void OnStart(String[] args)
        {
            if (this._failedStartup)
                Environment.Exit(this.ExitCode);

            this._timer.Start();
        }

        /// <summary>
        /// The stop of the service (when the stop button in services.msc is pushed) or during: net stop _service_
        /// </summary>
        protected override void OnStop()
        {
            this._timer.Stop();
        }

        /// <summary>
        /// Pausing the service stops the timer
        /// </summary>
        protected override void OnPause()
        {
            this._timer.Stop();

            base.OnPause();
        }

        /// <summary>
        /// Resuming the service starts the timer
        /// </summary>
        protected override void OnContinue()
        {
            this._timer.Start();

            base.OnContinue();
        }

        #endregion
    }
}
